package xyz.xtt.exchange.service.impl;

import static xyz.xtt.common.asset.AssertUtils.isFalse;
import static xyz.xtt.common.asset.AssertUtils.isTrue;

import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.primitives.Longs;
import com.tongtong.share.params.VideoAuditingParams;
import com.tongtong.share.response.AuditResponse;
import com.tongtong.share.response.BatchImageAuditingResponse;
import com.tongtong.share.response.VideoAuditResponse;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.api.enums.AssetTypeEnum;
import xyz.xtt.asset.api.enums.OwnerTypeEnum;
import xyz.xtt.asset.api.enums.SecondEnum;
import xyz.xtt.asset.client.response.AssetAccountResponse;
import xyz.xtt.asset.client.response.AssetAllInfoResponse;
import xyz.xtt.asset.client.response.AssetVo;
import xyz.xtt.asset.client.response.BlindBoxDetailResponse;
import xyz.xtt.common.asset.AssertUtils;
import xyz.xtt.common.starter.cache.CacheManager;
import xyz.xtt.common.starter.lock.RedisLock;
import xyz.xtt.equity.api.enums.BenefitEnum;
import xyz.xtt.exchange.constants.CheckLimitTypeEnum;
import xyz.xtt.exchange.constants.DimensionalTypeEnum;
import xyz.xtt.exchange.constants.ErrorMessage;
import xyz.xtt.exchange.entity.TblAssetAudit;
import xyz.xtt.exchange.exception.ChainException;
import xyz.xtt.exchange.service.AssetClientService;
import xyz.xtt.exchange.service.CheckLimitService;
import xyz.xtt.exchange.service.IInnerService;
import xyz.xtt.exchange.service.IRedisCacheService;
import xyz.xtt.exchange.service.ITblAssetAuditService;
import xyz.xtt.exchange.service.ITblMerchantInfoService;
import xyz.xtt.exchange.service.IUserLikeService;
import xyz.xtt.exchange.service.NftService;
import xyz.xtt.exchange.service.ThirdService;
import xyz.xtt.exchange.vo.AuditCheckResult;
import xyz.xtt.exchange.vo.BlindBoxDetailVO;
import xyz.xtt.exchange.vo.BlindBoxListVO;
import xyz.xtt.exchange.vo.ImageAuditingVo;
import xyz.xtt.exchange.vo.MintRequestExRequest;
import xyz.xtt.exchange.vo.TblBlindBoxDetailVO;
import xyz.xtt.exchange.vo.VideoAuditingVo;
import xyz.xtt.user.client.response.UserInfoResponse;

/**
 * @Description:
 * @Date: 2024/11/20/
 * @Author: gzm
 */
@Slf4j
@Service
@RefreshScope
public class NftServiceImpl implements NftService {
	@Autowired
	private ITblMerchantInfoService iTblMerchantInfoService;

	@Value("${asset.mint.type:JPG,PNG,WEBP,SVG,TIFF,RAW,JPEG}")
	private String[] imgTypes;

	@Value("${asset.mint.openCheckLimit:true}")
	private Boolean openMintCheckLimit;

	/**
	 * 日请求总数
	 */
	@Value("${asset.mint.totalReqDayLimit:100}")
	private Long mintTotalReqDayLimit;
	/**
	 * 每天成功的上限
	 */
	@Value("${asset.mint.successDayLimit:10}")
	private Long mintSuccessDayLimit;

	/**
	 * 连续错误上限
	 */
	@Value("${asset.mint.continuousErrDayLimit:10}")
	private Long mintContinuousErrDayLimit;
	/**
	 * 日错误上限
	 */
	@Value("${asset.mint.totalErrDayLimit:50}")
	private Long mintTotalErrDayLimit;

	@Value("${asset.nft.nftListPageSize:20}")
	private Integer nftListPageSize;

	@Value("${asset.upchain.fees:9.9}")
	private BigDecimal upchainFees;

	@Value("${asset.mint.pirce:0}")
	private BigDecimal mintPrice;

	@Value("${asset.mint.max.price:10000}")
	private BigDecimal maxPriceNERemintType;

	@Value("${asset.mint.tokenDelay:30}")
	private Integer mintTokenDealy;
	@Value("${asset.mint.secondTypeShelfTimeMinutes:5}")
	private Integer secondTypeShelfTimeMinutes;

	@Value("${asset.mint.canShelf:true}")
	private boolean canShelf;

	@Value("${auth.check.frequency:1440}")
	private Long authCheckFrequency;

	@Value("${asset.rose.fakeStart}")
	private String fakeStart;
	@Autowired
	private CacheManager cacheManager;

	private static final Integer maxMintAmount = 6;
	private static final Integer minMintAmount = 3;
	@Autowired
	private CheckLimitService checkLimitService;
	@Autowired
	private RedisLock redisLock;
	@Autowired
	private AssetClientService assetClientService;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private ITblAssetAuditService iTblAssetAuditService;

	@Autowired
	private IRedisCacheService redisCacheService;

	@Autowired
	private ThirdService thirdService;
//	@Autowired
//	private ITblUserDeliveryAddressService iTblUserDeliveryAddressService;
	@Autowired
	private IUserLikeService iUserLikeService;

	private static Integer AIImgConsumeCount = 1;
	private static String AIImgConsumeMsg = "AI生图次数减少";
//	@Autowired
//	private TblAssetServiceImpl tblAssetServiceImpl;
//	@Autowired
//	private ITblBlindBoxDetailService iTblBlindBoxDetailService;
	@Autowired
	private IInnerService iInnerService;
	/**
	 * 是否需要实名认证，默认需要
	 */
	@Value("${auth.check.switch:true}")
	private boolean checkAuthSwitch;
//	/**
//	 * 获取nft详情
//	 *
//	 * @param goodsId 资产编号
//	 * @return NftDetailsVo
//	 */
//	@Override
//	public NftDetailsVo getNftDetailsById(String goodsId) {
//		NftDetailsVo nftDetailsVo = null;
//		MPJLambdaWrapper<TblAsset> query = JoinWrappers
//				.lambda(TblAsset.class)
//				.select(TblAsset::getId, TblAsset::getGoodsId, TblAsset::getAssetNo, TblAsset::getAssetName, TblAsset::getDescription, TblAsset::getPrice, TblAsset::getUnit, TblAsset::getAmount, TblAsset::getFirstType, TblAsset::getAuthorId, TblAsset::getOwnerId, TblAsset::getCooperationId, TblAsset::getCollectionId)
//				.select(TblAssetStaticResource::getFileType, TblAssetStaticResource::getFileUri)
//				.selectAs(TblAsset::getAssetNo, NftDetailsVo::getTokenId)
//				.select(TblAssetExt::getSeqNo)
//				.from(x -> x.selectAll().eq(TblAsset::getGoodsId, goodsId))
//				.select(TblAssetExt::getChainId, TblAssetExt::getChainName, TblAssetExt::getChainTxHash, TblAssetExt::getReferProtocol)
//				.leftJoin(TblAssetExt.class, TblAssetExt::getAssetId, TblAsset::getId)
//				.select(TblAssetStaticResource::getLogoUri)
//				.leftJoin(TblAssetStaticResource.class, TblAssetStaticResource::getAssetId, TblAsset::getId);
//
//		nftDetailsVo = query.one(NftDetailsVo.class);
//		if (nftDetailsVo != null) {
//			// 填充买卖家【昵称、头像】
//			Long sellUid = Longs.tryParse(nftDetailsVo.getAuthorId());
//			Long buyUid = Longs.tryParse(nftDetailsVo.getOwnerId());
//			Set<Long> uids = Sets.newHashSet(sellUid, buyUid);
//			Map<Long, TblUser> userMap = queryUsers(uids);
//			nftDetailsVo.setBuyerNickname(getUserField(userMap, buyUid, TblUser::getNickname));
//			nftDetailsVo.setBuyerAvatar(getUserField(userMap, buyUid, TblUser::getAvatarUri));
//			nftDetailsVo.setSellerNickname(getUserField(userMap, sellUid, TblUser::getNickname));
//			nftDetailsVo.setSellerAvatar(getUserField(userMap, sellUid, TblUser::getAvatarUri));
//			// 转换分类名称
//			nftDetailsVo.setCategoryDescription(AssetTypeEnum.queryConvert(nftDetailsVo.getFirstType()).desc());
//			// 设置所属系列
//			String collectionId = nftDetailsVo.getCollectionId();
//			Long tryParseCollId = Longs.tryParse(collectionId);
//			// 如果是默认风格，不用去查了
//			if (Objects.nonNull(tryParseCollId) && tryParseCollId.longValue() > 0) {
//				// 加缓存
//				TblCollection tblCollection = cacheManager
//						.cacheObj(() -> collectionMapper.selectById(tryParseCollId), ExchangeCache.TBL_COLLECTION, collectionId);
//				if (Objects.nonNull(tblCollection)) {
//					nftDetailsVo.setCollectionDescription(tblCollection.getFieldStrValue(TblCollection::getDescription));
//					nftDetailsVo.setCoverImg(tblCollection.getFieldStrValue(TblCollection::getCoverImg));
//				}
//			}
//		}
//		nftDetailsVo.setCurrentDataTime(System.currentTimeMillis());
//		return nftDetailsVo;
//	}

//	@Override
//	public List<NftListVo> getNftListByUidV2(String uid, Integer currPage, Integer pageSize, String queryType, int businessType, int orderType) {
//		Long lUid = Long.parseLong(uid);
//		// 我拥有的
//		if (queryType.equals("0")) {
//			MPJLambdaWrapper<TblAssetAccount> query = JoinWrappers
//					.lambda(TblAssetAccount.class)
//					.select(TblAsset::getId, TblAsset::getAssetName, TblAsset::getDescription, TblAsset::getPrice, TblAsset::getGoodsId)
//					.select(TblAsset::getUnit, TblAsset::getFirstType, TblAsset::getSecondType, TblAsset::getPopularityRate)
//					.select(TblAssetAccount::getAmount)
//					.select(TblAssetStaticResource::getLogoUri)
//					.leftJoin(TblAsset.class, TblAsset::getId, TblAssetAccount::getAssetId)
//					.leftJoin(TblAssetStaticResource.class, TblAssetStaticResource::getAssetId, TblAssetAccount::getAssetId)
//					.leftJoin(TblAssetExt.class, TblAssetExt::getAssetId, TblAssetAccount::getAssetId)
//					.ne(TblAsset::getAuthorId, uid)
//					.eq(TblAssetAccount::getOwnerId, lUid)
//					.eq(-1 < businessType, TblAsset::getFirstType, businessType)
//					// 不显示不上链数据，
//					.eq(TblAssetExt::getUpChain, UpChainEnum.YES.code())
//					.gt(TblAssetAccount::getAmount, 0)
//					.orderBy(true, orderType != 0, TblAsset::getCreateDatetime)
//					.last(getCurrentPage(currPage, pageSize));
//			return assetAccountMapper.selectJoinList(NftListVo.class, query);
//		}
//		// 我铸造的
//		if (queryType.equals("1")) {
//			return getMyNftList(uid, currPage, pageSize, businessType, orderType, UpChainEnum.YES);
//		}
//		// 我生产的
//		if (queryType.equals("3")) {
//			return getMyNftList(uid, currPage, pageSize, businessType, orderType, UpChainEnum.NO);
//		}
//		return null;
//	}

//	private String getCurrentPage(Integer currPage, Integer pageSize) {
//		return String.format("limit %d, %d", Math.max(((currPage - 1) * pageSize), 0), pageSize);
//	}

//	private List<NftListVo> getMyNftList(String uid, Integer currPage, Integer pageSize, int businessType, int orderType, UpChainEnum upChainEnum) {
//		MPJLambdaWrapper<TblAsset> wrapper = JoinWrappers
//				.lambda(TblAsset.class)
//				.select(TblAsset::getId, TblAsset::getAssetName, TblAsset::getDescription, TblAsset::getPrice, TblAsset::getGoodsId)
//				.select(TblAsset::getUnit, TblAsset::getAmount, TblAsset::getFirstType, TblAsset::getSecondType, TblAsset::getPopularityRate)
//				.select(TblAssetStaticResource::getLogoUri)
//				.leftJoin(TblAssetStaticResource.class, TblAssetStaticResource::getAssetId, TblAsset::getId)
//				.leftJoin(TblAssetExt.class, TblAssetExt::getAssetId, TblAsset::getId)
//				.eq(TblAsset::getAuthorId, uid)
//				.eq(TblAssetExt::getUpChain, upChainEnum.code())
//				.eq(-1 < businessType, TblAsset::getFirstType, businessType)
//				.orderBy(true, orderType != 0, TblAsset::getCreateDatetime);
//
//		if (UpChainEnum.YES.equals(upChainEnum)) {
//			wrapper
//					.leftJoin(TblAssetAccount.class, on -> on
//							.eq(TblAssetAccount::getOwnerId, TblAsset::getAuthorId)
//							.eq(TblAssetAccount::getAssetId, TblAsset::getId))
//					.gt(TblAssetAccount::getAmount, 0);
//		}
//		wrapper.last(getCurrentPage(currPage, pageSize));
//		return assetMapper.selectJoinList(NftListVo.class, wrapper);
//	}

//	/**
//	 * @param uid 用户id
//	 * @return List<NftListVo>
//	 */
//	@Override
//	public List<NftListVo> getNftListByUid(String uid, Integer currPage, Integer pageSize, String queryType, int businessType, int orderType) {
//		List<Integer> list = Arrays.asList(
//				// AssetTypeEnum.EXCEPT.code(),
//				AssetTypeEnum.PFPS.code(), AssetTypeEnum.ELEMENT.code(), AssetTypeEnum.INTEREST.code(), AssetTypeEnum.PHOTO.code(), AssetTypeEnum.MUSIC
//						.code(), AssetTypeEnum.DESIGN.code(), AssetTypeEnum.LAND.code(), AssetTypeEnum.BUSINESS_CERTIFICATE.code());
//		NftQueryParam params = NftQueryParam
//				.builder()
//				.businessType(businessType)
//				.orderType(orderType)
//				.pageSize(pageSize)
//				.currPage(currPage)
//				.uid(Long.parseLong(uid))
//				.startIndex(currPage <= 0 ? 0 : (currPage - 1) * pageSize)
//				.build();
//		params.setStrUid(params.getUid().toString());
//		List<NftListVo> resLi = new ArrayList();
//		if (queryType.equals("0")) {/** -----拥有的----- **/
//			/** ------查询1155------- **/
//			resLi = assetAccountMapper.getNft1155List(params);
//			/** ------查询721------- **/
//			List<NftListVo> nft721List = assetAccountMapper.getNft721List(params);
//			resLi.addAll(nft721List);
//			return (resLi.size() <= pageSize ? resLi : resLi.stream().skip(params.getStartIndex()).limit(pageSize).toList());
//		} else {/** -----铸造的----- **/
//			resLi = assetAccountMapper.getCastNftList(params);
//			return resLi;
//		}
//	}

	/**
	 * 分页获取系列nft列表
	 *
	 * @param collectionId 系列ID
	 * @return List<NftListVo>
	 */
//	@Override
//	public List<NftListVo> getCollectionNftListById(Long collectionId, Integer currPage, Integer pageSize) {
//		MPJLambdaWrapper<TblAsset> nftWrapper = JoinWrappers
//				.lambda(TblAsset.class)
//				.select(TblAsset::getGoodsId, TblAsset::getAssetName, TblAsset::getDescription, TblAsset::getPrice, TblAsset::getUnit, TblAsset::getAmount)
//				.from(x -> x.selectAll().eq(TblAsset::getCollectionId, collectionId))
//				.select(TblAssetStaticResource::getLogoUri)
//				.leftJoin(TblAssetStaticResource.class, TblAssetStaticResource::getAssetId, TblAsset::getId);
//
//		IPage<NftListVo> page = assetMapper.selectJoinPage(new Page<>(currPage, pageSize), NftListVo.class, nftWrapper);
//		return page.getRecords();
//	}

	/*
	 * 查询买卖家信息
	 */
//	public Map<Long, TblUser> queryUsers(Collection<Long> uids) {
//		if (CollectionUtil.isEmpty(uids)) {
//			return null;
//		}
//		// 新铸造的nfc命中
//		// 不可变map后续不要操作
//		if (uids.size() == 1) {
//			Long uid = uids.iterator().next();
//			TblUser cahceUser = userService.infoWithUserIdCache(uid);
//			return Objects.nonNull(cahceUser) ? Map.of(uid, cahceUser) : Maps.newHashMap();
//		} else if (uids.size() == 2) {
//			List<Long> uidList = uids.stream().collect(toList());
//			return userService.queryUserWithCache(uidList.get(0), uidList.get(1));
//		}
//		List<TblUser> users = userService.queryUserInfo(uids);
//		return users.stream().collect(Collectors.toMap(TblUser::getAppUserId, Function.identity(), (a, b) -> b));
//	}
//
//	private String getField(TblUser seller, Function<? super TblUser, String> mapper) {
//		return Optional.ofNullable(seller).map(mapper).filter(StringUtils::isNotBlank).orElse(StringUtils.EMPTY);
//	}
//
//	public String getUserField(Map<Long, TblUser> userMap, Long uid, Function<? super TblUser, String> mapper) {
//		if (!userMap.containsKey(uid)) {
//			return StringUtils.EMPTY;
//		}
//		TblUser tblUser = userMap.get(uid);
//		return getField(tblUser, mapper);
//	}

//	@Override
//	public List<NftListVo> list(Integer currPage, String type, String searchKey) {
//		List<Integer> queryTypes = AssetTypeEnum.queryNftTypes(type);
//		// 传了值 但不正确的情况下
//		if (CollectionUtil.isEmpty(queryTypes)) {
//			return Lists.newArrayList();
//		}
//		int pageSize = nftListPageSize;
//		currPage = Optional.ofNullable(currPage).filter(Objects::nonNull).filter(x -> x > 0).orElse(1);
//		String page = String.format("limit %d, %d", ((currPage - 1) * pageSize), pageSize);
//
//		// List<Integer> notIn =
//		// Arrays.asList(AssetTypeEnum.BUSINESS_CERTIFICATE.code(),
//		// AssetTypeEnum.LAND.code());
//		MPJLambdaWrapper<TblAsset> leftJoin = JoinWrappers
//				.lambda(TblAsset.class)
//				.select(TblAsset::getGoodsId, TblAsset::getFirstType, TblAsset::getSecondType, TblAsset::getAssetName, TblAsset::getAmount, TblAsset::getUnit, TblAsset::getPrice, TblAsset::getDescription, TblAsset::getPopularityRate, TblAsset::getAuthorId)
//				.select(TblAsset::getSellPattern)
//				.in(TblAsset::getFirstType, queryTypes)
//				// 没有搜索 先不处理
//				// .and(StringUtils.isNotBlank(searchKey), xx -> xx.like(TblAsset::getAssetName,
//				// searchKey).or().like(TblAsset::getDescription, searchKey))
//				// .eq(TblAssetExt::getUpChain, UpChainEnum.YES.code())
//				// 只展示平台铸造的
//				.eq(TblAsset::getOwnerType, OwnerTypeEnum.PLATFORM.code())
//				.orderByDesc(TblAsset::getCreateDatetime)
//				.select(TblAssetStaticResource::getLogoUri, TblAssetStaticResource::getAssetId)
//				.leftJoin(TblAssetStaticResource.class, TblAssetStaticResource::getAssetId, TblAsset::getId)
//				.leftJoin(TblAssetExt.class, TblAssetExt::getAssetId, TblAsset::getId)
//				.last(page);
//
////				.from(x -> x
////						.selectAll()
////						.in(TblAsset::getFirstType, queryTypes)
////						.and(StringUtils.isNotBlank(searchKey), xx -> xx.like(TblAsset::getAssetName, searchKey).or().like(TblAsset::getDescription, searchKey))
////						// .notIn(TblAsset::getFirstType, notIn)
////						.orderByDesc(TblAsset::getCreateDatetime)
////						.last(page))
//
//		List<NftListVo> list = leftJoin.list(NftListVo.class);
//		// 查询用户列表信息
//		Set<Long> userIds = new HashSet<>();
//		list.stream().peek(x -> userIds.add(x.getAuthorId())).toList();
//
//		// 查询销售数据
//		Map<Long, Long> seqNo = redisCacheService.getSeqNo();
//		// 根据用户ID 获取用户信息
//		Map<Long, TblUser> userList = queryUsers(userIds);
//		list = list.stream().peek(x -> {
//			Long markNum = seqNo.get(x.getGoodsId());
//			x.setAuthorName(getUserField(userList, x.getAuthorId(), TblUser::getNickname));
//			x.setAuthorUrl(getUserField(userList, x.getAuthorId(), TblUser::getAvatarUri));
//			x.setMarketNum(Objects.isNull(markNum) ? 0 : markNum);
//		}).toList();
//		return list;
//	}

	private boolean mintImgCheck(String imageUrl) {
		try {
			URL url = new URL(imageUrl);
			String path = url.getPath();
			String pathLowerCase = path.toLowerCase();
			boolean anyMatch = Stream.of(imgTypes).map(String::toLowerCase).anyMatch(x -> pathLowerCase.endsWith(x));
			log.info("mintImgCheck imageUrl:{},anyMatch:{},imgTypes:{}", imageUrl, anyMatch, Arrays.toString(imgTypes));
			return anyMatch;
		} catch (MalformedURLException e) {
			log.info("mintImgCheck ex: {}", e.getMessage(), e);
		}
		return false;
	}

	@Override
	public AuditCheckResult mintBeforeCheck(UserInfoResponse userInfo, AssetTypeEnum assetType, String displayUri, String checkText) {
		// 日请求总数检查
		// 日成功铸造总数检查
		// 日连续失败数检查
		// 日总失败数检查
		if (Objects.isNull(userInfo)) {
			throw new ChainException(ErrorMessage.USER_NOT_EXIST);
		}
		if (Objects.isNull(assetType)) {
			throw new ChainException(ErrorMessage.ASSET_TYPE_ERR);
		}
		String uid = String.valueOf(userInfo.getAppUserId());
		// =0 是默认风格 默认风格的uid是0
		// String displayUri = mintRequestVo.getDisplayUri();
		boolean checkDomain = checkLimitService.checkDomain(displayUri);
		if (!checkDomain) {
			throw new ChainException(ErrorMessage.ILLEGAL_DOMAIN_REQUEST);
		}
		// 文件类型
		if (!mintImgCheck(displayUri)) {
			throw new ChainException(ErrorMessage.UNSUPPORTED_FILE_TYEPS);
		}
		if (Objects.equals(Boolean.TRUE, openMintCheckLimit)) {
			Predicate<Long> dayTotalRequestCheck = (Long totalRequest) -> (totalRequest >= mintTotalReqDayLimit);
			Predicate<Long> daySuccessCheck = (Long succ) -> (succ >= mintSuccessDayLimit);
			Predicate<Long> dayContinuousFailCheck = (Long continuous) -> (continuous >= mintContinuousErrDayLimit);
			Predicate<Long> dayTotalFailCheck = (Long totalfail) -> (totalfail >= mintTotalReqDayLimit);
			checkLimitService.checkLimit(uid, CheckLimitTypeEnum.MINT, dayTotalRequestCheck, daySuccessCheck, dayContinuousFailCheck, dayTotalFailCheck);
		}
		return checkLimitService.auditCheck(uid, CheckLimitTypeEnum.MINT, checkText, displayUri);
	}

	private void checkSubmit(String uid, String mintToken) {
		isTrue(StringUtils.isBlank(mintToken), ErrorMessage.UNKNOWN_ERROR);
		String mintTokenKey = mintTokenKey(uid);
		isFalse(stringRedisTemplate.hasKey(mintTokenKey), ErrorMessage.SUBMIT_TIMEOUT);
		String beforeToken = stringRedisTemplate.opsForValue().get(mintTokenKey);
		isFalse(Objects.equals(mintToken, beforeToken), ErrorMessage.SUBMIT_TIMEOUT);
	}

//	@Transactional(rollbackFor = Exception.class)
//	@Override
//	public MintResponse mint(String uid, MintRequestVo mintRequestVo) {
//		String mintToken = mintRequestVo.getMintToken();
//		checkSubmit(uid, mintToken);
//		String mintTokenKey = mintTokenKey(uid);
//		// 提交的token和服务端的一样
//		if (tblAssetTransactionService.checkAuth(uid)) {
//			throw new ChainException(ErrorMessage.NEED_AUTHENTICATION);
//		}
//		String key = String.format("nft:mint:lock:%s", uid);
//		String val = UUID.randomUUID().toString();
//		boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(key, val, 1, TimeUnit.MINUTES);
//		if (lock) {
//			try {
//				MintResponse doAssetMint = doAssetMint(uid, mintRequestVo);
//				log.info("mint delete token:{}", mintTokenKey);
//				stringRedisTemplate.delete(mintTokenKey);
//				return doAssetMint;
//			} finally {
//				// 拿到锁后把本次的token删除
//				if (val.equals(stringRedisTemplate.opsForValue().get(key))) {
//					stringRedisTemplate.delete(key);
//				}
//			}
//		}
//		throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
//	}

//	public MintResponse doAssetMint(String uid, MintRequestVo mintRequestVo) {
//		AssetTypeEnum assetType = AssetTypeEnum.DESIGN;
//		TblUser appUserInfo = cacheManager.cacheObj(() -> userService.findByAppUserId(uid), ExchangeCache.TBL_USER, uid);
//		// 前置校验
//		AuditCheckResult mintBeforeCheck = mintBeforeCheck(appUserInfo, assetType, mintRequestVo.getDisplayUri(), mintRequestVo.checkText());
//		Boolean isReplace = Optional
//				.ofNullable(mintBeforeCheck)
//				.map(AuditCheckResult::getImgResponse)
//				.filter(x -> StringUtils.isNoneBlank(x.getAssetUrl()))
//				.map(AuditResponse::isReplace)
//				.orElse(Boolean.FALSE);
//		// 处理替换url
//		if (Objects.equals(Boolean.TRUE, isReplace)) {
//			String assetUrl = mintBeforeCheck.getImgResponse().getAssetUrl();
//			log.info("doAssetMint isReplace url old:{},new:{}", mintRequestVo.getDisplayUri(), assetUrl);
//			mintRequestVo.setDisplayUri(assetUrl);
//		}
//		List<MintDataVo> attributes = Lists.newArrayList();
//		attributes.add(new MintDataVo("类型", assetType.desc()));
//		attributes.add(new MintDataVo("数量", String.valueOf(mintRequestVo.getAmount())));
//		attributes.add(new MintDataVo("创作时间", String.valueOf(System.currentTimeMillis())));
//		String bizId = IdUtil.getSnowflakeNextIdStr();
//		MintRequest mintRequest = MintRequest
//				.builder()
//				.description(mintRequestVo.getDescription())
//				.image(mintRequestVo.getDisplayUri())
//				.name(mintRequestVo.getAssetName())
//				.attributes(attributes)
//				.authorId(uid)
//				.referProtocol(String.valueOf(ReferProtocolEnum.ERC_1155.getCode()))
//				.bizId(bizId)
//				.chainId(4)
//				.assetType(assetType.name())
//				.amount(mintRequestVo.getAmount())
//				.price(mintPrice)
//				.unit(PayUnitEnum.CASH.code())
//				.bizType("nft")
//				.sellEndDatetime(0L)
//				.sellEndDatetime(0L)
//				.upChain(mintRequestVo.getUpChain())
//				.ownerType(OwnerTypeEnum.USER.code())
//				.build();
//		MintResponse assetMintResponse = assetClientService.mint(uid, mintRequest);
//		if (Objects.nonNull(assetMintResponse)) {
//			checkLimitService.plusDayValue(uid, CheckLimitTypeEnum.MINT, DimensionalTypeEnum.SUCC);
//			return MintResponse.builder().assetId(assetMintResponse.getAssetId()).goodsId(bizId).build();
//		}
//		return null;
//	}

//	@Override
//	public MintResponse assetMint(String uid, MintRequestVo mintRequestVo) {
//		return doAssetMint(uid, mintRequestVo);
//	}

//	private MintResponse doMint(String uid, MintRequestVo mintRequestVo) {
//		AssetTypeEnum assetType = AssetTypeEnum.DESIGN;
//		TblUser appUserInfo = cacheManager.cacheObj(() -> userService.findByAppUserId(uid), ExchangeCache.TBL_USER, uid);
//		// 前置校验
//		mintBeforeCheck(appUserInfo, assetType, mintRequestVo.getDisplayUri(), mintRequestVo.checkText());
//		long assetId = IdUtil.getSnowflakeNextId();
//		TblAsset asset = mintRequestVo.buildGroundAsset(uid, assetId, assetId, assetType, mintPrice);
//		TblAssetExt assetExt = mintRequestVo.buildGroundAssetExt(assetId, asset.getId(), "4", ReferProtocolEnum.ERC_1155);
//		TblAssetStaticResource staticResource = mintRequestVo.buildStaticResource(assetId, FileTypeEnum.IMG);
////		TblAssetTransaction buildTransaction = tblAssetTransactionService
////				.buildTransaction(asset, uid, DealStateEnum.NOT_PAYED, OrderTypeEnum.PERSIONAL_MINT, SellPatternEnum.MINT, BigDecimal.ONE);
//		MetaDataParams buildMetaData = buildMetaData(asset, staticResource, assetType, appUserInfo);
//		String metaData = JSONUtil.toJsonStr(buildMetaData);
//		asset.setMetaData(metaData);
//		assetExt.setMetadata(metaData);
//		boolean saveAssetResult = this.iTblAssetService.save(asset);
//		boolean saveAssetExtResult = this.iTblAssetExtService.save(assetExt);
//		boolean saveAssetStaticResult = this.iTblAssetStaticResourceService.save(staticResource);
////		boolean saveTranscation = this.tblAssetTransactionService.save(buildTransaction);
//		if (saveAssetResult && saveAssetExtResult && saveAssetStaticResult) {
//			// 成功次数+1
//			checkLimitService.plusDayValue(uid, CheckLimitTypeEnum.MINT, DimensionalTypeEnum.SUCC);
//			BigDecimal amount = new BigDecimal(String.valueOf(asset.getAmount()));
//			iAssetAccountService.initAccountAmount(assetId, Longs.tryParse(uid), ReferProtocolEnum.ERC_7211, amount);
//		}
//		return MintResponse.builder().assetId(assetId).goodsId(asset.getGoodsId()).build();
//	}

//	@Override
//	public NftInterestDetailsVo getNftDetails(String goodsId, String uid) {
//		Long uidL = Long.parseLong(uid);
//		AssetBaseInfo assetBaseInfo = iTblAssetService.baseInfo(goodsId);
//		if (null == assetBaseInfo) {
//			return null;
//		}
//		// 组合数据
//		Long assetId = assetBaseInfo.getAsset().getId();
//		NftInterestDetailsVo build = NftInterestDetailsVo.build(assetBaseInfo);
//
//		// 查询权益信息
//		List<TblAssetEntitlement> assetEntitlement = getAssetEntitlement(assetId);
//		List<InterestVo> interestVo = DozerUtil.transforList(assetEntitlement, InterestVo.class);
//
//		// 查询我是否拥有资产
//		TblAssetAccount account = new LambdaQueryChainWrapper<>(tblAssetAccountMapper)
//				.eq(TblAssetAccount::getAssetId, assetId)
//				.eq(TblAssetAccount::getOwnerId, uidL)
//				.gt(TblAssetAccount::getAmount, 0)
//				.one();
//		// 存在资产
//		if (Objects.nonNull(account)) {
//			build.setOwnerId(uid);
//			buildDeliverResult(interestVo, assetId, uidL);
//			// 可以加群
//			build.setIsAddGroup(true);
//			// 可以赠送
//			if (Objects.equals(OwnerTypeEnum.USER.code(), assetBaseInfo.getAsset().getOwnerType())
//					&& Objects.equals(assetBaseInfo.getAssetExt().getUpChain(), UpChainEnum.YES.code())) {
//				build.setIsGiveAway(true);
//			}
//		}
//		build.setInterestVoList(interestVo);
//		// 处理用户名称 头像
//		Long sellUid = Longs.tryParse(build.getAuthorId());
//		Long buyUid = Longs.tryParse(build.getOwnerId());
//		Set<Long> uids = Sets.newHashSet(sellUid, buyUid, uidL);
//		Map<Long, TblUser> userMap = queryUsers(uids);
//		build.setBuyerNickname(getUserField(userMap, buyUid, TblUser::getNickname));
//		build.setBuyerAvatar(getUserField(userMap, buyUid, TblUser::getAvatarUri));
//		build.setSellerNickname(getUserField(userMap, sellUid, TblUser::getNickname));
//		build.setSellerAvatar(getUserField(userMap, sellUid, TblUser::getAvatarUri));
//		build.setIssuer(getUserField(userMap, sellUid, TblUser::getNickname));
//		build.setFoundryMan(getUserField(userMap, sellUid, TblUser::getNickname));
//		build.setIssuerPlatform(getUserField(userMap, sellUid, TblUser::getNickname));
//		TblUser tblUser = userMap.get(uidL);
//		build.setActiveParam(tblUser.getGender().toString());
//
//		// 查询交易
//		TblAssetTransaction notPaiedTransaction = tblAssetTransactionService.queryNotPaiedPersonalMintUpChaninOrder(assetId, uid);
//		if (Objects.nonNull(notPaiedTransaction)) {
//			build.setUpChainPaying(true);
//		}
//
//		// @TODO 处理群ID
//		if (Objects.nonNull(build.getIsAddGroup()) && build.getIsAddGroup()) {
//			build.setImGroupId(iAssetGroupService.getImGroupId(assetBaseInfo.getAsset().getId()));
//		}
//		// 查询是否有群ID
//
//		// 1155资产设置剩余数量
//		if (Objects.equals(assetBaseInfo.getAssetExt().getReferProtocol(), ReferProtocolEnum.ERC_1155.getDescription())) {
//			if (!Objects.equals(uidL, Long.valueOf(assetBaseInfo.getAsset().getAuthorId()))) {
//				account = new LambdaQueryChainWrapper<>(tblAssetAccountMapper)
//						.eq(TblAssetAccount::getAssetId, assetId)
//						.eq(TblAssetAccount::getOwnerId, Long.valueOf(assetBaseInfo.getAsset().getAuthorId()))
//						.one();
//			}
//			build.setGoodsRemain(account != null ? account.getAmount().intValue() : 0);
//		} else {
//			build.setGoodsRemain(0);
//		}
//		build.setCurrentDataTime(System.currentTimeMillis());
//		build.setPublicityPeriod(assetBaseInfo.getAssetExt().checkPublicityPeriodEnd());
//		build.setCurrAvatar(getUserField(userMap, uidL, TblUser::getAvatarUri));
//		if (canShelf) {
//			// 判断上架状态 uid==authorId&&uid==ownerId&&sellPattern==0&&bizType==NFT&&Balance g 0
//			if (Objects.equals(uidL, Long.valueOf(assetBaseInfo.getAsset().getAuthorId()))
//					&& Objects.equals(uidL, Long.valueOf(assetBaseInfo.getAsset().getOwnerId()))
//					&& Objects.equals(assetBaseInfo.getAsset().getSellPattern(), SellPatternEnum.NORMAL.code())
//					&& BizTypeEnum.NFT.dbType().equalsIgnoreCase(assetBaseInfo.getAsset().getBizType()) && Objects.nonNull(account)) {
//				build.setChainOver5Days(true);
//			}
//
//			// 重铸类型需要多判断5天的条件 铸造权超过5天
//			if (assetBaseInfo.getAsset().getSecondType().equals(SecondEnum.MINT_POWER.getCode()) && DateUtil
//					.between(new Date(assetBaseInfo.getAsset().getCreateDatetime()), new Date(
//							System.currentTimeMillis()), DateUnit.MINUTE) < secondTypeShelfTimeMinutes) {
//				build.setChainOver5Days(false);
//			}
//		}
//		// 查询卡列表 todo物流信息
//		queryCardList(assetBaseInfo, uidL, build);
//		// 查询最大购买价格
//		Long oldGoodsId = assetBaseInfo.getAsset().getParentId();
//		BigDecimal bigDecimal = tblAssetTransactionService.buyMaxPriceWithHistory(uid, oldGoodsId);
//		build.setMaxPrice(bigDecimal.toString());
//		build.setMaxPriceNERemintType(maxPriceNERemintType.divide(new BigDecimal(assetBaseInfo.getAsset().getAmount()), 2, RoundingMode.DOWN).toString());
//		// 查询是否认证 把认证时间返回
//		build.setAuthorAuthDate(queryAuthDate(assetBaseInfo.getAsset().getAuthorId()));
//		return build;
//	}

//	private Long queryAuthDate(String authorId) {
//		UserInfoResponse userInfo = iInnerService.userInfo(Longs.tryParse(authorId));
////		UserVo userInfo = userService.getUserInfo(authorId);
//		if (Objects.nonNull(userInfo)) {
//			return userInfo.getAuthBefore();
//		}
//		return 0L;
//	}

//	private void queryCardList(Long assetId, Long uidL, NftInterestDetailsVo build) {
//		// 获取用户卡片信息
//		List<TblAssetCardDto> cardList = getUserCardList(assetId, uidL);
//		if (cardList.isEmpty()) {
//			build.setCardList(Collections.emptyList());
//			return;
//		}
//
//		// 过滤出需要补充物流信息的卡片 ID 列表
//		List<Long> idList = filterCardIdsForLogistics(cardList);
//		if (idList.isEmpty()) {
//			build.setCardList(cardList);
//			return;
//		}
//
//		// 获取物流订单信息
//		Map<String, BusinessOrderDto> orderMap = getLogisticsOrderMap(uidL, idList);
//		if (orderMap.isEmpty()) {
//			build.setCardList(cardList);
//			return;
//		}
//
//		// 补充物流信息到卡片列表
//		supplementLogisticsInfo(cardList, orderMap);
//		build.setCardList(cardList);
//	}

//	private List<TblAssetCardDto> getUserCardList(Long assetId, Long uidL) {
//		CardInfoRequest cardInfoRequest = new CardInfoRequest();
//		cardInfoRequest.setAssetId(String.valueOf(assetId));
//		cardInfoRequest.setOwnerId(String.valueOf(uidL));
//		List<TblAssetCardDto> userCardInfo = iInnerService.getUserCardInfo(cardInfoRequest);
//		return Objects.isNull(userCardInfo) ? Collections.emptyList() : userCardInfo;
//	}

//	private List<Long> filterCardIdsForLogistics(List<TblAssetCardDto> cardList) {
//		return cardList.stream().filter(card -> card.getReceiveState() == 1).map(TblAssetCardDto::getId).collect(Collectors.toList());
//	}

//	private Map<String, BusinessOrderDto> getLogisticsOrderMap(Long uidL, List<Long> idList) {
//		BusinessOrderRequest businessOrderRequest = new BusinessOrderRequest();
//		businessOrderRequest.setGoodsType(1);
//		businessOrderRequest.setAppUserId(uidL);
//		businessOrderRequest.setGoodsIds(idList);
//		ApiResult<List<BusinessOrderDto>> listApiResult = assetClient.selectListByGoodsIds(businessOrderRequest);
//		if (listApiResult.isOk() && listApiResult.getData() != null) {
//			return listApiResult.getData().stream().collect(Collectors.toMap(BusinessOrderDto::getGoodsId, Function.identity(), (v1, v2) -> v1));
//		}
//		return Collections.emptyMap();
//	}

//	private void supplementLogisticsInfo(List<TblAssetCardDto> cardList, Map<String, BusinessOrderDto> orderMap) {
//		cardList.forEach(card -> {
//			if (orderMap.containsKey(card.getId().toString())) {
//				BusinessOrderDto businessOrderDto = orderMap.get(card.getId().toString());
//				card.setLogisticsNumber(businessOrderDto.getTransportNo());
//				card.setLogisticsCompanyName(businessOrderDto.getTransportCompany());
//			}
//		});
//	}

//	private void queryCardList(AssetBaseInfo assetBaseInfo, Long uidL, NftInterestDetailsVo build) {
//		CardInfoRequest cardInfoRequest = new CardInfoRequest();
//		cardInfoRequest.setAssetId(assetBaseInfo.getAsset().getId());
//		cardInfoRequest.setOwnerId(uidL);
//		ApiResult<List<TblAssetCardDto>> userCardInfo = assetClient.getUserCardInfo(cardInfoRequest);
//		List<TblAssetCardDto> cardList = userCardInfo.getData();
//		// 补充物流信息
//		List<Long> idList = cardList.stream().filter(x -> x.getReceiveState() == 1).map(TblAssetCardDto::getId).toList();
//		if(!CollectionUtil.isEmpty(idList)){
//			BusinessOrderRequest businessOrderRequest = new BusinessOrderRequest();
//			businessOrderRequest.setGoodsType(1);
//			businessOrderRequest.setAppUserId(uidL);
//			businessOrderRequest.setGoodsIds(idList);
//			ApiResult<List<BusinessOrderDto>> listApiResult = assetClient.selectListByGoodsIds(businessOrderRequest);
//			if(listApiResult.isOk()){
//				//listApiResult转换成map
//				Map<String, BusinessOrderDto> collect = listApiResult.getData().stream().collect(Collectors.toMap(BusinessOrderDto::getGoodsId, Function.identity()));
////				List<Long> list = listApiResult.getData().stream().map(BusinessOrderDto::getReceiveAddressId).toList();
//				cardList.forEach(card ->{
//					// 补充物流
//					BusinessOrderDto businessOrderDto = collect.get(card.getId().toString());
//					if(Objects.nonNull(businessOrderDto)){
//						card.setLogisticsNumber(businessOrderDto.getTransportNo());
//						card.setLogisticsCompanyName(businessOrderDto.getTransportCompany());
//					}
//				});
//			}
//		}
//		build.setCardList(cardList);
//	}

//	public void buildDeliverResult(List<InterestVo> list, Long assetId, Long uid) {
//		if (list.isEmpty()) {
//			return;
//		}
//		// 兑换权益列表
//		List<Long> deliverIds = getAssetEntitlementDeliver(assetId, uid);
////		Set<Long> deliverIds = assetEntitlementDeliver.stream().map(TblAssetEntitlementDeliver::getId).collect(toSet());
////		if (assetEntitlementDeliver.isEmpty()) {
////			return list;
////		}
////		HashSet<String> deliverIds = new HashSet<>();
////		for (TblAssetEntitlementDeliver vo : assetEntitlementDeliver) {
////			if (vo.getResult().equals(1)) {
////				deliverIds.add(vo.getEntitlementId().toString());
////			}
////		}
//		list = list.stream().peek(x -> {
//			if (deliverIds.contains(Longs.tryParse(x.getId()))) {
//				x.setResult(String.valueOf(DeliverResult.SUCC.code()));
//			}
//		}).toList();
//	}

//	public List<Long> getAssetEntitlementDeliver(Long assetId, Long userId) {
//		// 查询权益兑换详情
//		MPJLambdaWrapper<TblAssetEntitlementDeliver> query = JoinWrappers
//				.lambda(TblAssetEntitlementDeliver.class)
//				.select(TblAssetEntitlementDeliver::getEntitlementId)
//				.eq(TblAssetEntitlementDeliver::getAssetId, assetId)
//				.eq(TblAssetEntitlementDeliver::getResult, DeliverResult.SUCC.code())
//				.eq(TblAssetEntitlementDeliver::getAppUserId, userId);
//		return query.list(Long.class);
//	}

	/**
	 * 根据资产 获取 权益列表
	 * 
	 * @param assetId
	 * @return
	 */
//	public List<TblAssetEntitlement> getAssetEntitlement(Long assetId) {
//		return cacheManager
//				.cacheList(() -> new LambdaQueryChainWrapper<>(tblAssetEntitlementMapper)
//						.eq(TblAssetEntitlement::getAssetId, assetId)
//						.list(), ExchangeCache.TBL_ASSET_ENTITLEMENT, String.valueOf(assetId));
//	}

//	@Override
//	public NftInterestDetailsVo getNftDetailsInterestById(String goodsId, String uid) {
//		NftInterestDetailsVo nftDetailsVo = null;
//		MPJLambdaWrapper<TblAsset> query = JoinWrappers
//				.lambda(TblAsset.class)
//				.select(TblAsset::getId, TblAsset::getGoodsId, TblAsset::getAssetNo, TblAsset::getAssetName, TblAsset::getDescription, TblAsset::getPrice, TblAsset::getUnit, TblAsset::getAmount, TblAsset::getFirstType, TblAsset::getAuthorId, TblAsset::getOwnerId, TblAsset::getCooperationId, TblAsset::getCollectionId)
//				.selectAs(TblAsset::getAssetNo, NftInterestDetailsVo::getTokenId)
//				.selectAs(TblAsset::getCreateDatetime, NftInterestDetailsVo::getIssuerDate)
//				.selectAs(TblAsset::getCreateDatetime, NftInterestDetailsVo::getFoundryDate)
//				.from(x -> x.selectAll().eq(TblAsset::getGoodsId, goodsId))
//				.select(TblAssetExt::getChainId, TblAssetExt::getChainName, TblAssetExt::getChainTxHash, TblAssetExt::getReferProtocol, TblAssetExt::getShowType, TblAssetExt::getChainBlockNum, TblAssetExt::getChainTime)
//				.leftJoin(TblAssetExt.class, TblAssetExt::getAssetId, TblAsset::getId)
//				.select(TblAssetStaticResource::getLogoUri)
//				.leftJoin(TblAssetStaticResource.class, TblAssetStaticResource::getAssetId, TblAsset::getId);
//		nftDetailsVo = query.one(NftInterestDetailsVo.class);
//		MPJLambdaWrapper<TblUser> userQuery = JoinWrappers.lambda(TblUser.class).select(TblUser::getGender).eq(TblUser::getAppUserId, uid);
//		TblUser one1 = userQuery.one();
//		nftDetailsVo.setActiveParam(String.valueOf(one1.getGender()));
//
//		Long assertId = nftDetailsVo.getId();
//		int sum = 0;
//		// 查询交易关联表
//		if (nftDetailsVo.getReferProtocol().equals(ReferProtocolEnum.ERC_1155.getDescription())) {
//			MPJLambdaWrapper<TblAssetAccount> relationQuery = JoinWrappers
//					.lambda(TblAssetAccount.class)
//					.select(TblAssetAccount::getAssetId, TblAssetAccount::getOwnerId, TblAssetAccount::getAmount)
//					.eq(TblAssetAccount::getOwnerId, uid)
//					.eq(TblAssetAccount::getAssetId, assertId);
//			List<TblAssetAccount> li = relationQuery.list();
//			sum = li != null ? li.stream().map(TblAssetAccount::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add).intValue() : 0;
//		}
//
//		List<TblAssetEntitlement> qyLi = cacheManager.cacheList(() -> {
//			MPJLambdaWrapper<TblAssetEntitlement> assetEntitlementQuery = JoinWrappers.lambda(TblAssetEntitlement.class);
//			assetEntitlementQuery
//					.select(TblAssetEntitlement::getId, TblAssetEntitlement::getAssetId, TblAssetEntitlement::getDescription, TblAssetEntitlement::getAmount, TblAssetEntitlement::getAcceptName, TblAssetEntitlement::getName, TblAssetEntitlement::getAcceptDesc, TblAssetEntitlement::getAcceptStartTime, TblAssetEntitlement::getAcceptEndTime, TblAssetEntitlement::getRequirement, TblAssetEntitlement::getRequestParam, TblAssetEntitlement::getRequestUrl, TblAssetEntitlement::getBusinesSource, TblAssetEntitlement::getExchangeDesc, TblAssetEntitlement::getEquityType)
//					.eq(TblAssetEntitlement::getAssetId, assertId);
//			return assetEntitlementQuery.list(TblAssetEntitlement.class);
//		}, ExchangeCache.TBL_ASSET_ENTITLEMENT, String.valueOf(assertId));
//
//		List<InterestVo> collect = qyLi.stream().map(x -> {
//			String s = JSONUtil.toJsonStr(x);
//			InterestVo interestVo = JSONUtil.toBean(s, InterestVo.class);
//			return interestVo;
//		}).collect(Collectors.toList());
//		if (sum > 0) {
//			nftDetailsVo.setOwnerId(uid);
//			if (collect != null && collect.size() > 0) {
//				MPJLambdaWrapper<TblAssetEntitlementDeliver> deliverMPJLambdaWrapper = JoinWrappers.lambda(TblAssetEntitlementDeliver.class);
//				deliverMPJLambdaWrapper
//						.select(TblAssetEntitlementDeliver::getEntitlementId, TblAssetEntitlementDeliver::getResult)
//						.eq(TblAssetEntitlementDeliver::getAppUserId, Long.parseLong(uid))
//						.in(TblAssetEntitlementDeliver::getEntitlementId, qyLi.stream().map(x -> x.getId()).collect(Collectors.toList()));
//				List<TblAssetEntitlementDeliver> list = deliverMPJLambdaWrapper.list();
//				for (TblAssetEntitlementDeliver one : list) {
//					for (InterestVo vo : collect) {
//						if (one.getEntitlementId() == Long.parseLong(vo.getId())) {
//							vo.setResult(one.getResult() != null ? one.getResult().toString() : "");
//						}
//					}
//				}
//
//			}
//		}
//		nftDetailsVo.setInterestVoList(collect);
//		if (nftDetailsVo != null) {
//			// 填充买卖家【昵称、头像】
//			Long sellUid = Longs.tryParse(nftDetailsVo.getAuthorId());
//			Long buyUid = Longs.tryParse(nftDetailsVo.getOwnerId());
//			Set<Long> uids = Sets.newHashSet(sellUid, buyUid);
//			Map<Long, TblUser> userMap = queryUsers(uids);
//			nftDetailsVo.setBuyerNickname(getUserField(userMap, buyUid, TblUser::getNickname));
//			nftDetailsVo.setBuyerAvatar(getUserField(userMap, buyUid, TblUser::getAvatarUri));
//			nftDetailsVo.setSellerNickname(getUserField(userMap, sellUid, TblUser::getNickname));
//			nftDetailsVo.setSellerAvatar(getUserField(userMap, sellUid, TblUser::getAvatarUri));
//
//			nftDetailsVo.setIssuer(getUserField(userMap, sellUid, TblUser::getNickname));
//			nftDetailsVo.setFoundryMan(getUserField(userMap, sellUid, TblUser::getNickname));
//			nftDetailsVo.setIssuerPlatform(getUserField(userMap, sellUid, TblUser::getNickname));
//			// 转换分类名称
//			nftDetailsVo.setCategoryDescription(AssetTypeEnum.queryConvert(nftDetailsVo.getFirstType()).desc());
//			// 设置所属系列
//			String collectionId = nftDetailsVo.getCollectionId();
//			Long tryParseCollId = Longs.tryParse(collectionId);
//			// 如果是默认风格，不用去查了
//			if (Objects.nonNull(tryParseCollId) && tryParseCollId.longValue() > 0) {
//				// 加缓存
//				TblCollection tblCollection = cacheManager
//						.cacheObj(() -> collectionMapper.selectById(tryParseCollId), ExchangeCache.TBL_COLLECTION, collectionId);
//				if (Objects.nonNull(tblCollection)) {
//					nftDetailsVo.setCollectionDescription(tblCollection.getFieldStrValue(TblCollection::getDescription));
//					nftDetailsVo.setCoverImg(tblCollection.getFieldStrValue(TblCollection::getCoverImg));
//				}
//			}
//		}
//		return nftDetailsVo;
//	}

//	private TblCollection queryOrDefault(Long uid, Long cooperationId) {
//		// 默认风格直接new出来
//		if (Objects.equals(cooperationId, 0L)) {
//			return null;
//		}
//		TblCollection collection = cacheManager
//				.cacheObj(() -> iTblCollectionService.info(cooperationId, uid), ExchangeCache.TBL_COLLECTION, String.valueOf(uid), String
//						.valueOf(cooperationId));
//		if (Objects.isNull(collection)) {
//			throw new ChainException(ErrorMessage.USER_NOT_EXIST_COLLECTION);
//		}
//		return collection;
//	}

//	private MetaDataParams buildMetaData(TblAsset asset, TblAssetStaticResource staticResource, AssetTypeEnum assetType, TblUser appUserInfo) {
//		MetaDataParams params = new MetaDataParams();
//		params.setDescription(asset.getDescription());
////		params.setExternal_url(staticResource.getDisplayUri());
//		params.setImage(staticResource.getDisplayUri());
//		params.setName(asset.getAssetName());
//		List<MetaDataAttribute> attributes = Lists.newArrayList();
//		attributes.add(new MetaDataAttribute("类型", assetType.desc()));
//		attributes.add(new MetaDataAttribute("数量", String.valueOf(asset.getAmount())));
//		attributes.add(new MetaDataAttribute("创作者", appUserInfo.getNickname()));
//		attributes.add(new MetaDataAttribute("创作时间", String.valueOf(asset.getCreateDatetime())));
//		params.setAttributes(attributes);
//		return params;
//	}

	@Override
	public String getAiImgToImg(Long uId, String imgUrl, String style) {
		// 加锁
		String key = String.format("ai_img_to_img:%s", uId);
		String val = UUID.randomUUID().toString();
		boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(key, val, 1, TimeUnit.MINUTES);

		if (!lock) {
			log.error("锁定中重复调用， uid:{}", uId);
			return null;
		}
		try {
			// 查询数次
			Map<String, Integer> userBenefits = iInnerService.getUserBenefits(uId, BenefitEnum.AI_PIC_THEME.getCode());
			isTrue(userBenefits.isEmpty(), ErrorMessage.AI_CODE_RUN_SHORT);
			Integer total = userBenefits.get(BenefitEnum.AI_PIC_THEME.getCode());
			// 次数不足
			if (Objects.isNull(total) || total.equals(0)) {
				throw new ChainException(ErrorMessage.AI_CODE_RUN_SHORT);
			}
			// 查询 用户是否存在 Ai 生图效果
			String stringApiResult = iInnerService.imageToImage(imgUrl, style);
			isTrue(StringUtils.isBlank(stringApiResult), ErrorMessage.AI_IMG_TO_TMG_FAILED);
			// 减少次数
			Boolean userBenefitConsumed = iInnerService.userBenefitConsumed(uId, BenefitEnum.AI_PIC_THEME.getCode(), AIImgConsumeCount, null, AIImgConsumeMsg);
			isFalse(userBenefitConsumed, ErrorMessage.AI_CODE_RUN_SHORT);
			return stringApiResult;
		} finally {
			if (val.equals(stringRedisTemplate.opsForValue().get(key))) {
				stringRedisTemplate.delete(key);
			}
		}
	}

	private String mintTokenKey(String uid) {
		String key = String.format("nft:mint:uid:%s", uid);
		return key;
	}

	/**
	 * 创建铸造token
	 * 
	 * @param uid
	 * @return
	 */
	@Override
	public String mintToken(String uid) {
		String mintToken = IdUtil.getSnowflakeNextIdStr();
		String key = mintTokenKey(uid);
		Duration ofMillis = Duration.ofMinutes(mintTokenDealy);
		stringRedisTemplate.opsForValue().set(key, mintToken, ofMillis);
		return mintToken;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Long mintEx(String uid, MintRequestExRequest mintRequestVo) {
		AssetTypeEnum assetType = AssetTypeEnum.queryConvert(mintRequestVo.getFirstType());
		String mintToken = mintRequestVo.getMintToken();
		checkSubmit(uid, mintToken);
		if (mintRequestVo.isVideo()) {
			isFalse(mintRequestVo.checkVideo(), ErrorMessage.VIDEO_MINT_PARAM_EX);
		} else {
			isFalse(mintRequestVo.checkImage(), ErrorMessage.IMAGE_MINT_PARAM_EX);
		}
		UserInfoResponse appUserInfo = iInnerService.userInfo(Longs.tryParse(uid));
		Boolean checkAuth = iInnerService.checkAuth(uid, authCheckFrequency);
		// 如果不是视频先审核
		// 是否需要进行实名认证
		if (Objects.equals(checkAuth, Boolean.TRUE)) {
			throw new ChainException(ErrorMessage.NEED_AUTHENTICATION);
		}
		// 获取用户商家信息
		Boolean merchant = iTblMerchantInfoService.judgeMerchantPer(uid);

		// 盲盒参数校验
		if (assetType.equals(AssetTypeEnum.BLIND_BOX)) {
			// 需要认证商户
			if (!merchant) {
				// throw new ChainException(ErrorMessage.NEED_AUTHENTICATION);
			}
			// 判断盲盒图片数量
			if (mintRequestVo.getFilePaths().size() > maxMintAmount || mintRequestVo.getFilePaths().size() < minMintAmount) {
				throw new ChainException(ErrorMessage.IMAGE_MINT_PARAM_EX);
			}
		}

		String imagePath = mintRequestVo.getImagePath();
		String context = mintRequestVo.checkText();
//		if (mintRequestVo.isVideo()) {
//			// 如果是视频,不用去审核视频的地址,异步处理
//			imagePath = StringUtils.EMPTY;
//		}
		AuditCheckResult mintBeforeCheck = mintBeforeCheck(appUserInfo, assetType, imagePath, context);

		String mintTokenKey = mintTokenKey(uid);

		String key = String.format("nft:mint:lock:%s", uid);
		String val = UUID.randomUUID().toString();
		boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(key, val, 1, TimeUnit.MINUTES);
		// 如果个人传权益包ID ，是否可以？
		if (lock) {
			try {

				TblAssetAudit buildTblAssetAudit = mintRequestVo.buildTblAssetAudit(uid, assetType, 2);
				Long auditId = mintRequestVo.getAuditId();
				if (Objects.nonNull(auditId) && auditId.longValue() > 0) {
					boolean failReMint = this.iTblAssetAuditService
							.failReMint(auditId, mintRequestVo.getVideoPath(), mintRequestVo.getImagePath(), mintRequestVo.getAssetName(), mintRequestVo
									.getDescription());
					isFalse(failReMint, ErrorMessage.FAIL_RE_MINT_EX);
				} else {
					Boolean isReplace = Optional
							.ofNullable(mintBeforeCheck)
							.map(AuditCheckResult::getImgResponse)
							.filter(x -> StringUtils.isNotBlank(x.getAssetUrl()))
							.map(AuditResponse::isReplace)
							.orElse(Boolean.FALSE);
					log.info("mint img mintBeforeCheck:{}", JSONUtil.toJsonStr(mintBeforeCheck));
					if (Objects.equals(Boolean.TRUE, isReplace)) {
						String assetUrl = mintBeforeCheck.getImgResponse().getAssetUrl();
						log.info("doAssetMint isReplace url old:{},new:{}", mintRequestVo.getImagePath(), assetUrl);
						buildTblAssetAudit.setImgPath(assetUrl);
					}
					// 处理替换url
					Integer checkAuditType = mintRequestVo.checkAuditType();
					switch (checkAuditType) {
					case 1:
						// 视频
						VideoAuditingVo videoAuditing = videoAuditing(uid, String.valueOf(buildTblAssetAudit.getId()), mintRequestVo);
						buildTblAssetAudit.setVideoAuditRequestId(videoAuditing.getJobId());
						buildTblAssetAudit.setVideoPath(videoAuditing.getUrl());
						break;
					case 2:
						// 批量图片
						ImageAuditingVo imageAuditing = imageAuditing(mintRequestVo);
						buildTblAssetAudit.setVideoAuditRequestId(imageAuditing.getJobId());
						buildTblAssetAudit.setFileList(JSONUtil.toJsonStr(imageAuditing.getFilePaths()));
						break;
					default:
						buildTblAssetAudit.setResult(1);
					}

					int amount = mintRequestVo.getAmount().intValue();
					// 能用的次数
					String operateDesc = "铸造" + buildTblAssetAudit.getAssetName();
					int userBenefitConsumeAsMuchAsPossible = iInnerService
							.userBenefitConsumeAsMuchAsPossible(Longs.tryParse(uid), "FREE_MINT", amount, buildTblAssetAudit.getId(), operateDesc);
					// 本次铸造实际消耗的次数
					buildTblAssetAudit.setRightAmount(userBenefitConsumeAsMuchAsPossible);
					// 设置商家
					buildTblAssetAudit.setOwnerType(merchant ? OwnerTypeEnum.AGENT.code() : OwnerTypeEnum.USER.code());

					try {
						boolean save = iTblAssetAuditService.save(buildTblAssetAudit);
						isFalse(save, ErrorMessage.MINT_RESULT_EX);
						log.info("mintEx save:{}", save);
						// 提交成功就算一次
						checkLimitService.plusDayValue(uid, CheckLimitTypeEnum.MINT, DimensionalTypeEnum.SUCC);
						log.info("mint delete token:{}", mintTokenKey);
						stringRedisTemplate.delete(mintTokenKey);
					} catch (Exception e) {
						iInnerService.userBenefitRecover(Longs.tryParse(uid), auditId, operateDesc + "取消");
						log.info("userBenefitRecover auditId:{},ex:{}", auditId, e.getMessage(), e);
						throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
					}
				}
				return buildTblAssetAudit.getId();
			} finally {
				// 拿到锁后把本次的token删除
				if (val.equals(stringRedisTemplate.opsForValue().get(key))) {
					stringRedisTemplate.delete(key);
				}
			}
		}
		throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
	}

	private ImageAuditingVo imageAuditing(MintRequestExRequest mintRequestVo) {
		if (mintRequestVo.getFilePaths().isEmpty()) {
			throw new ChainException(ErrorMessage.FILEPATH_AUDIT_EX);
		}
		BatchImageAuditingResponse batchImageAuditing = iInnerService.batchImageAuditing(String.join(",", mintRequestVo.getFilePaths()));
		String jobId = Optional
				.ofNullable(batchImageAuditing)
				.map(BatchImageAuditingResponse::getRequestId)
				.filter(StringUtils::isNotBlank)
				.orElse(StringUtils.EMPTY);
		if (StringUtils.isNotBlank(jobId)) {
			log.info("filePaths:{}, jobId:{}", String.join(",", mintRequestVo.getImagePath(), jobId));
			return ImageAuditingVo.builder().jobId(jobId).filePaths(batchImageAuditing.getUrls()).build();
		}
		log.info("filePaths:{}, response:{}", String.join(",", mintRequestVo.getImagePath(), jobId), JSONUtil.toJsonStr(batchImageAuditing));
		throw new ChainException(ErrorMessage.FILEPATH_AUDIT_EX);
	}

	private VideoAuditingVo videoAuditing(String userId, String assetId, MintRequestExRequest mintRequestVo) {
		VideoAuditingParams request = new VideoAuditingParams();
		request.setImageUrl(mintRequestVo.getImagePath());
		request.setVideoUrl(mintRequestVo.getVideoPath());
		request.setUserId(userId);
		request.setAssetId(assetId);
		request.setWidth(mintRequestVo.getWidth());
		request.setHeight(mintRequestVo.getHeight());
		request.setDuration(mintRequestVo.getDuration());
		VideoAuditResponse videoAuditing = iInnerService.videoAuditing(request);
		if (Objects.nonNull(videoAuditing)) {
			String jobId = videoAuditing.getJobId();
			String url = videoAuditing.getUrl();
			log.info("videoPath:{}, jobId:{}", url, jobId);
			return VideoAuditingVo.builder().jobId(jobId).url(url).build();
		}
		log.info("videoPath:{}, response:{}", JSONUtil.toJsonStr(request), JSONUtil.toJsonStr(videoAuditing));
		throw new ChainException(ErrorMessage.VIDEO_AUDIT_EX);
	}

//	@Override
//	public MintResponse reMint(String uid, @Valid ReMintRequest reMintRequest) {
//		AssetBaseInfo baseInfo = iTblAssetService.baseInfo(reMintRequest.getGoodsId());
//		TblAsset asset = baseInfo.getAsset();
//		TblAssetExt assetExt = baseInfo.getAssetExt();
//		TblAssetStaticResource assetStatic = baseInfo.getAssetStaticResource();
//		List<MetaDataAttribute> attributes = Lists.newArrayList();
//		String metadata = assetExt.getMetadata();
//		MetaDataParams bean = JSONUtil.toBean(metadata, MetaDataParams.class);
//		if (Objects.nonNull(bean)) {
//			attributes = bean.getAttributes();
//		}
//		List<MintDataVo> mintAttr = Lists.newArrayList();
//		for (MetaDataAttribute att : attributes) {
//			String trait_type = att.getTrait_type();
//			Object value = att.getValue();
//			mintAttr.add(new MintDataVo(trait_type, String.valueOf(value)));
//		}
//		AssetTypeEnum assetType = AssetTypeEnum.queryConvert(asset.getFirstType());
//		String goodsId = asset.getGoodsId();
//		String referProtocol = assetExt.getReferProtocol();
//		Long seqNo = 0L;
//		// 如果是7211从0开始
//		if (ReferProtocolEnum.ERC_7211.getDescription().equals(referProtocol)) {
//			seqNo = 1L;
//		}
//		MintRequest mintRequest = MintRequest
//				.builder()
//				.description(asset.getDescription())
//				.externalUrl(assetStatic.getFileUri())
//				.image(assetStatic.getDisplayUri())
//				.name(asset.getAssetName())
//				.attributes(mintAttr)
//				.authorId(String.valueOf(uid))
//				.referProtocol(referProtocol)
//				.assetType(assetType.name())
//				.bizId(IdUtil.getSnowflakeNextIdStr())
//				.chainId(Ints.tryParse(assetExt.getChainId()))
//				.amount(1)
//				.price(asset.getPrice())
//				.unit(asset.getUnit())
//				.bizType(BizTypeEnum.NFT.dbType())
//				.sellEndDatetime(assetExt.getSellStartDatetime())
//				.sellEndDatetime(assetExt.getSellEndDatetime())
//				.showState(ShowStateEnum.DOWN.code())
//				.ownerType(OwnerTypeEnum.USER.code())
//				.parentId(Longs.tryParse(goodsId))
//				.seqNo(seqNo)
//				.build();
//		ApiResult<xyz.xtt.pay.client.response.MintResponse> mint = assetClient.mint(uid, mintRequest);
//		xyz.xtt.pay.client.response.MintResponse response = Optional.ofNullable(mint).filter(ApiResult::isOk).map(ApiResult::getData).orElse(null);
//		AssertUtils.isNull(response, ErrorMessage.MINT_RESULT_EX);
//		return MintResponse.builder().assetId(response.getAssetId()).goodsId(response.getBizId()).build();
//	}

	@Override
	public List<BlindBoxListVO> getBlindBoxList(String uid, int boxType, Integer currPage, Integer pageSize, int secondType) {
		AssertUtils.isTrue(boxType <= 0, ErrorMessage.ARGUMENT_NOT_VALID);
		List<AssetVo> assetVos = iInnerService.queryAssetType(currPage, uid, AssetTypeEnum.getEnumByCode(boxType));
		List<BlindBoxListVO> result = new ArrayList<>(assetVos.size());
		Map<String, List<BlindBoxDetailResponse>> details = new HashMap<>();
		if (CollectionUtil.isEmpty(assetVos)) {
			return result;
		}
		if (secondType > 0) {
			// 需要获取更多图片 亚姐
			assetVos = assetVos.stream().filter(x -> x.getSecondType() == secondType).toList();
			if (CollectionUtil.isEmpty(assetVos)) {
				return result;
			}
			List<BlindBoxDetailResponse> queryBlindBoxDetail = iInnerService.queryBlindBoxDetail(assetVos.stream().map(AssetVo::getGoodsId).toList());
			details.putAll(queryBlindBoxDetail.stream().collect(Collectors.groupingBy(BlindBoxDetailResponse::getGoodsId)));
		}
		// 查询是否点赞
		Set<String> likeIds = iUserLikeService.getUserLikeCache(Long.valueOf(uid));
		assetVos.forEach(assetVo -> {
			BlindBoxListVO blindBoxListVO = new BlindBoxListVO();
			BeanUtils.copyProperties(assetVo, blindBoxListVO);
			if (details.containsKey(assetVo.getGoodsId())) {
				blindBoxListVO.setMoreImg(details.get(assetVo.getGoodsId()).stream().map(BlindBoxDetailResponse::getFileUri).toList());
			}
			blindBoxListVO.setLikeState(likeIds.contains(assetVo.getGoodsId()) ? 1 : 0);
			result.add(blindBoxListVO);
		});
		result.sort(Comparator.comparing((BlindBoxListVO box) -> {
			String popularity = box.getPopularity();
			try {
				return new BigDecimal(popularity);
			} catch (NumberFormatException e) {
				log.warn("Invalid popularity value: {}", popularity);
				return BigDecimal.ZERO; // 或者返回其他默认值
			}
		}).reversed());
		return result;
	}

	@Override
	public BlindBoxDetailVO getBlindBoxDetailInfo(String uid, String goodsId) {
		AssetAllInfoResponse assetBaseInfo = iInnerService.infoGoodsId(goodsId);
		AssetAccountResponse accountInfoUnCheckAmount = iInnerService
				.accountInfoUnCheckAmount(Long.valueOf(assetBaseInfo.getAsset().getOwnerId()), assetBaseInfo.getAsset().getId());
		BigDecimal amount = accountInfoUnCheckAmount.getAmount();
		BlindBoxDetailVO result = new BlindBoxDetailVO();
		result.setAssetId(assetBaseInfo.getAsset().getId());
		result.setGoodsId(assetBaseInfo.getAsset().getGoodsId());
		result.setSurplusNum(amount.intValue());
		result.setOriginalPrice(assetBaseInfo.getAsset().getGuidePrice().toString());
		result.setCurrentPrice(assetBaseInfo.getAsset().getPrice().toString());
		result.setDescription(assetBaseInfo.getAsset().getDescription());
		result.setAssetName(assetBaseInfo.getAsset().getAssetName());
		List<BlindBoxDetailResponse> list = iInnerService.queryBlindBoxDetail(Arrays.asList(assetBaseInfo.getAsset().getGoodsId()));
		result.setFileUri(list.stream().map(detail -> {
			TblBlindBoxDetailVO tblBlindBoxDetailVO = new TblBlindBoxDetailVO();
			BeanUtils.copyProperties(detail, tblBlindBoxDetailVO);
			return tblBlindBoxDetailVO;
		}).toList());
		return result;
	}

	@Override
	public Map<Integer, String> getCompetitionArea() {
		Map<Integer, String> collect = Arrays
				.stream(SecondEnum.values())
				.filter(x -> x.getFirstType() == AssetTypeEnum.MISS_ASIA_BLIND_BOX.code())
				.collect(Collectors.toMap(SecondEnum::getCode, SecondEnum::getDesc));
		return collect;
	}
}
